<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8"> <meta name="viewport" content="width=device-width">
    <title>从零开始的解析HWDB1.1数据之路</title>
    <meta name="viewport" content="width=device-width,initial-scale=1, shrink-to-fit=no">
    <!-- Bootstrap CSS -->
    <link rel="stylesheet"
          href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.0/dist/css/bootstrap.min.css"
          integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk"
          crossorigin="anonymous">
    <link rel="stylesheet"
          href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.5.0/styles/androidstudio.min.css">
<!--    <link rel="stylesheet" href="/web_template_css.css">-->
    <!-- this is highlight.js -->
    <script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
    <script id="MathJax-script" async
            src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js">
    </script>
    <script  src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"
    integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
    integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.0/dist/js/bootstrap.min.js"
    integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.5.0/highlight.min.js"></script>
    <style>
      img{
        display: block;
        height: auto;
        max-width: 100%;
      }
    </style>
  </head>
  <body>
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
        <a class="navbar-brand" href="#">kvrmnks</a>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
          <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarNav">
          <ul class="navbar-nav">
            <li class="nav-item active">
              <a class="nav-link" href="./../../../../../index.html" target="_self">Home <span class="sr-only">(current)</span></a>
            </li>
            <li class="nav-item">
              <a class="nav-link" href="./../../../../../blog.html">Blog</a>
            </li>
            <li class="nav-item">
              <a class="nav-link" href="./../../../../../about.html">About</a>
            </li>
          </ul>
        </div>
      </nav>



    <div class='container'>
      <p>本文旨在为自身后日回忆~~并非用于教学~~
<!--more--></p>

<p>本文强烈建议使用jupyter lab</p>

<hr>

<h2>第一步 得到数据集</h2>

<p><del>不说了</del></p>

<hr>

<h2>第二步 解析一个文件</h2>

<p>就来解析这个叫“1001-c.gnt”的文件吧</p>

<p>官网上有具体的文件格式</p>

<p>简单来说是，一个这样的文件中包含了多个图片</p>

<p><del>直接上代码好了</del></p>

<pre><code class="language-python">import numpy as np
import struct
def load_raw_data(id):
    path = &#39;../HWDB1.1trn_gnt/&#39; + str(id) + &#39;-c.gnt&#39;
    file = open(path, &#39;rb&#39;)
    features = []
    labels = []
    while file.read(1) != &#39;&#39;:
        file.seek(-1, 1)
        buf = file.read(4)
        if len(buf) != 4:
            break
        length_bytes = struct.unpack(&#39;&lt;I&#39;, buf)[0]
        tag_code = file.read(2)
        width = struct.unpack(&#39;&lt;H&#39;, file.read(2))[0]
        height = struct.unpack(&#39;&lt;H&#39;, file.read(2))[0]
        content = file.read(height*width)
        img = np.frombuffer(content, dtype=np.uint8).reshape(height,width)
        features.append(img)
        labels.append(char_dict[tag_code.decode(&#39;gb2312&#39;)])
    return np.array(features), np.array(labels)
</code></pre>

<p>char_dict就不放在这里了，太长了</p>

<p>这个函数的第一个返回值是一个ndarray，每个元素是一个灰度图片</p>

<p>第二个返回值是labels数组代表了每个图片分别属的类别</p>

<p>然后随便说一些细节吧</p>

<ol>
<li>每次读完一个图片之后通过</li>
</ol>

<pre><code class="language-python">if len(buf) != 4:
    break
</code></pre>

<p>来判断文件是不是读完了</p>

<ol>
<li>中文编码是gb2312格式的</li>
<li>读入文件的时候用np.frombuffer会快一点，尽量不要一个一个像素的读，py的速度太拉胯了</li>
<li>dtype=np.uint8 可以极限省内存</li>
</ol>

<hr>

<h2>第三步 看看图片长啥样</h2>

<pre><code class="language-python">import matplotlib.pyplot as plt
features, labels = load_raw_data(1001)
plt.imshow(features[0])
</code></pre>

<p><img src="1596034371418.jpg" style="zoom:33%;" /><img src="1596036378417.jpg" alt=""></p>

<p>同样也可以输出图片的大小
<code>python
print(features[0].shape)</code>
如果你多看几张图片的话就会发现，基本上每张图片的大小都是不一样的，这显然(显然吗？)不能直接用，我们需要先把图片都转换成一样的大小</p>

<hr>

<h2>第四步 图片处理</h2>

<p>以将图片最终转换成32*32为例</p>

<h3>偷工减料的方法</h3>

<p>pyTorch 有个叫做AdaptiveAvgPool2d的东西
导入pytorch的相关东西
<code>python
import torch.nn as nn
import torch
ft = nn.AdaptiveAvgPool2d((32, 32))</code>
为了使用pytorch就必须把原来图片的numpy形式转换成pytorch使用的Tensor形式
还要注意把数据格式改成float格式才能作为参数传到网络里
最后还要注意添加一维作为通道维
反正挺烦的
<code>python
img = torch.from_numpy(features[0])
img = torch.from_numpy(features[0]).float().view(1, features[0].shape[0], features[0].shape[1])
new_img = ft(img)</code>
可以再输出一下img的大小
<code>python
print(img.shape)</code>
可以发现变成了(1, 32, 32)，第一个1是指一个通道，不了解也没关系(
把图片plot出来看看</p>

<pre><code class="language-python">plt.imshow(new_img[0])
</code></pre>

<p><img src="1596035144870.jpg" style="zoom:50%;" />
虽然大小对了，但是图像完全走样了...</p>

<h3>手工缩放图像</h3>

<p>没想到好的办法，只能手动缩放了，这里主要使用了PIL的Image模块
<code>python
from PIL import Image</code>
幸运的是，Image可以通过numpy的ndarray直接生成灰度图
<code>python
img = Image.fromarray(features[0])</code>
假设我们想把图片转换成高h宽w（假设图片的原来大小为高x宽y）
不妨假设h=w=0好了~~好萌啊~~
我们就能得到图片的缩放比例
<code>python
h,w = 32,32
x,y = features[0].shape
ratio = min(h/x, w/y)</code>
然后通过PIL来进行图片的缩放
<code>python
x,y = int(ratio*x), int(ratio*y)
img = img.resize((y,x), Image.ANTIALIAS)</code>
resize的第一个参数是指要变换后的大小, <strong>这里有个坑点，排在前面的是width</strong>
第二个参数是指插值方法
如果你不知道到底做的对不对可以通过
<code>python
print(img.size) # 查看图片的大小
img.show() # 康康图片长啥样</code>
最后我们要把图片补成高h宽w（为什么还要补原因自己想去
没有太好的方法，我们就采用一种奇技淫巧
先创建一张空图
<code>python
new_img = Image.new(&#39;L&#39;,(w, h), 255)</code>
&#39;L&#39;代表为灰度图，第二个参数依旧是**width在前面**，255表示每个像素点都是255即白色
然后我们把之前resize的图片粘到这张空图的中间
<code>python
x,y = int((h-x)/2), int((w-y)/2)
new_img.paste(img, (y, x))</code>
paste的第二个参数表示img的左上角处于哪个位置，**width在前**
最后只需要从Image转会ndarray就好了
<code>python
arr = np.asarray(new_img)
plt.imshow(arr)</code>
发现效果好多了
<img src="1596036378417.jpg" alt=""></p>

<hr>

<h2>一些补充</h2>

<p>在缩放图片的时候可以引入一些随机因素，来提高模型的泛化能力
比如, 让图片不一定被放缩到最大
<code>python
h,w = 32,32
x,y = features[0].shape
ratio = min((h-np.random.randint(3,5))/x, (w-np.random.randint(3,5))/y)</code></p>


    </div>
    <script>
      hljs.initHighlightingOnLoad()
    </script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlightjs-line-numbers.js/2.5.0/highlightjs-line-numbers.min.js"></script>
  <script>
      hljs.initHighlightingOnLoad();
      hljs.initLineNumbersOnLoad();
  </script>
  </body>
</html>